home *** CD-ROM | disk | FTP | other *** search
- /* Program: mcc
- * By: Brent Callaghan
- * Date: July 1984
- *
- * Function: Runs the C compiler, passing all command line
- * arguments. If the compiler returns a non-zero
- * result, the syntax errors are merged with the
- * source and the user's editor is invoked. The
- * cursor is placed on the first line in error.
- * Exit from the editor re-invokes the C compiler.
- * This loop continues until the C compiler exits
- * to the linker, the source file is not changed,
- * or the user kills mcc with a keyboard interrupt
- * after exiting the editor.
- *
- * Environment variables EDITOR and COMPILER may
- * be used to set an alternative editor or compiler.
- *
- * ~~~ PUBLIC DOMAIN ~~~
- *
- * This program may be freely used and distributed
- * but I would rather you did not sell it.
- *
- ************************************************************
- */
-
- /* bugs: 1. only edits the first source file with errors. */
- /* 2. copies the temporary back onto the original even if */
- /* the original is newer */
-
- #if 0
- Mcc (Merge C Compiler) behaves just like a C for an error free
- compile. However, if the compiler finds syntax errors, it merges the
- error messages with the source and invokes your editor (default is vi)
- on the merged file. On exiting the editor it strips the merged
- messages and if the source file was modified it re-runs the compiler
- for another try.
-
- This posting contains a shell script and a C program with identical
- functionality. The C program is noticeably faster.
-
- Made in New Zealand --> Brent Callaghan @ Sun Microsystems
- uucp: sun!bcallaghan
- phone: (415) 691 6188
- #endif
-
- #include <stdio.h>
- #include <ctype.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- #ifdef BSD
- #include <strings.h>
- #define strchr index
- #define strrchr rindex
- #else
- #include <string.h>
- #endif
-
- extern char * getenv();
- static char *errname = "/tmp/errXXXXXX";
- static char mergename[128];
- static char *srcname;
- static char *editor, *edname, *compiler;
- static int pid, viedit, firsterr;
- static int chksum1, chksum2;
- static int filevar, linevar, msgvar;
- extern char *re_comp();
- static char errpat[1024], errpato[1024];
- static char *errdfa;
- extern char *braslist[], *braelist[];
-
- /*
- * Form 16 bit checksum of source line
- */
- int
- checksum(sum, line)
- register int sum;
- register char *line;
- {
- while (*line++) {
- if (sum & 1)
- sum = (sum >> 1) + 0x8000;
- else
- sum >>= 1;
-
- sum = (sum + *line) & 0xFFFF;
- }
- return sum;
- }
-
- int
- runc(argv, errname)
- char **argv;
- char *errname;
- {
- int status;
-
- switch (pid = fork()) {
- case 0: /* child */
- (void) freopen(errname, "w", stderr);
- execvp(compiler, argv);
- perror("Couldn't exec compiler");
- exit (1);
-
- case -1: /* Error */
- perror("Couldn't fork compiler");
- exit (1);
-
- default: /* Parent */
- while (wait(&status) != pid); /* wait for compile to finish */
- break;
- }
- return ((status >> 8) & 0xFF);
- }
-
- void
- listerrs(errname)
- char *errname;
- {
- FILE *errfile;
- char errline[BUFSIZ + 1];
-
- if ((errfile = fopen(errname, "r")) == NULL)
- return;
- while (fgets(errline, BUFSIZ, errfile) != NULL)
- (void) fputs(errline, stderr);
- (void) fclose(errfile);
- (void) unlink(errname);
- }
-
- void
- edit(mergename)
- char *mergename;
- {
- int status;
- char sfirsterr[6];
-
- switch (pid = fork()) {
- case 0: /* Child */
- if (viedit) {
- (void) sprintf(sfirsterr, "+%d", firsterr);
- (void) printf(" vi %s %s\n", sfirsterr, mergename);
- execlp(editor, "vi", sfirsterr, mergename, NULL);
- } else {
- (void) printf(" %s %s\n", edname, mergename);
- execlp(editor, edname, mergename, NULL);
- }
- perror("Couldn't exec editor");
- listerrs(errname);
- exit (1);
-
- case -1: /* Error */
- perror("Couldn't fork editor");
- listerrs(errname);
- exit (1);
-
- default: /* Parent */
- while (wait(&status) != pid); /* wait for editor to finish */
- break;
- }
- }
-
- int
- errinfo(errfile, srcname, errmsg)
- FILE *errfile;
- char *srcname, *errmsg;
- {
- static char errline[BUFSIZ + 1];
- char slineno[8];
- char *p1;
-
- for (;;) {
- /* get next line from error message file */
- if (fgets(errline, BUFSIZ, errfile) == NULL)
- return 0;
-
- errline[strlen(errline) - 1] = '\0'; /* trim newline */
- p1 = errline;
-
- /* does it match the pattern? */
- if (re_exec(p1, errdfa)) {
- sprintf(srcname, "%.*s", braelist[filevar] - braslist[filevar],
- braslist[filevar]);
- sprintf(slineno, "%.*s", braelist[linevar] - braslist[linevar],
- braslist[linevar]);
- sprintf(errmsg, "%.*s", braelist[msgvar] - braslist[msgvar],
- braslist[msgvar]);
- return atoi(slineno);
- }
- }
- }
-
- char *merge(errname, mergename)
- char *errname, *mergename;
- {
- FILE *errfile, *srcfile, *mergefile;
- int eof = 0, slineno, elineno, elines;
- static char firstname[128];
- char srcline[BUFSIZ + 1];
- char srcname[128], errmsg[80];
-
- if ((errfile = fopen(errname, "r")) == NULL) {
- perror(errname);
- exit (1);
- }
- if ((firsterr = errinfo(errfile, srcname, errmsg)) == 0)
- return NULL;
-
- if (access(srcname, 2) < 0) /* writeable ? */
- return NULL;
-
- if ((srcfile = fopen(srcname, "r")) == NULL) {
- perror(srcname);
- exit (1);
- }
- if (*mergename == '\0') {
- char *p = strrchr(srcname, '/');
- if (p == NULL)
- p = srcname;
- else
- p++;
- (void) sprintf(mergename, "/tmp/%d.%s", getpid(), p);
- }
- if ((mergefile = fopen(mergename, "w")) == NULL) {
- perror(mergename);
- exit (1);
- }
- slineno = 0;
- elineno = firsterr;
- elines = 0;
- (void) strcpy(firstname, srcname);
- chksum1 = 0;
-
- if (!viedit) {
- (void) fprintf(mergefile, ">>>><<<< (%d)\n", firsterr + 1);
- elines++;
- }
- while (!eof) {
- if (!(eof = (fgets(srcline, BUFSIZ, srcfile) == NULL))) {
- chksum1 = checksum(chksum1, srcline);
- (void) fputs(srcline, mergefile);
- }
- slineno++;
- while (slineno == elineno) {
- elines++;
- (void) fprintf(mergefile, ">>>> %s <<<<", errmsg);
- if ((elineno = errinfo(errfile, srcname, errmsg)) == 0
- || strcmp(firstname, srcname) != 0)
- (void) fprintf(mergefile, " (last error)\n");
- else
- (void) fprintf(mergefile, " (%d)\n", elineno + elines);
- }
- }
- (void) fclose(errfile);
- (void) fclose(srcfile);
- (void) fclose(mergefile);
- return (firstname);
- }
-
- /*
- * Strip out merged error messages and compute checksum
- */
- void
- unmerge(mergename, srcname)
- char *mergename, *srcname;
- {
- FILE *mergefile, *srcfile;
- char *p, srcline[BUFSIZ + 1];
- struct stat merge, src;
-
- if (stat(mergename, &merge) != 0) {
- perror(mergename);
- exit(1);
- }
-
- if (stat(srcname, &src) != 0) {
- perror(srcname);
- exit(1);
- }
-
- if (merge.st_mtime < src.st_mtime) { /* src is newer, don't */
- return; /* crong it from tmp */
- }
-
- if ((mergefile = fopen(mergename, "r")) == NULL) {
- perror(mergename);
- exit (1);
- }
- if ((srcfile = fopen(srcname, "w")) == NULL) {
- perror(srcname);
- exit (1);
- }
- chksum2 = 0;
- while (fgets(srcline, BUFSIZ, mergefile) != NULL) {
- for (p = srcline; isspace(*p); p++);
- if (strncmp(p, ">>>>", 4) != 0) {
- chksum2 = checksum(chksum2, srcline);
- (void) fputs(srcline, srcfile);
- }
- }
-
- (void) fclose(mergefile);
- (void) fclose(srcfile);
- }
-
- void
- quit()
- {
- (void) kill(pid, SIGTERM);
- (void) unlink(errname);
- (void) unlink(mergename);
- exit (1);
- }
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- char *p, *s, *d;
- int i, status, nvars;
-
- if ((editor = getenv("EDITOR")) == NULL)
- editor = "vi";
- edname = (edname = strrchr(editor, '/')) == NULL ? editor : edname + 1;
- viedit = strcmp(edname, "vi") == 0;
-
- if ((compiler = getenv("COMPILER")) == NULL)
- compiler = "cc";
- argv[0] = compiler;
-
- (void) mktemp(errname);
-
- signal(SIGINT, quit);
- signal(SIGTERM, quit);
- signal(SIGHUP, quit);
-
- if (p = getenv("ERRORPATTERN"))
- strcpy(errpat, p);
-
- nvars = 0;
-
- /* preprocess pattern to turn %f and %l into \(.*\) so that regex */
- /* will remember the file and line numbers. */
- for (s = errpat, d = errpato; *s;) {
- if (*s == '%' && s[1] == 'f') {
- *d++ = '\\'; *d++ = '('; *d++ = '.'; *d++ = '*';
- *d++ = '\\'; *d++ = ')';
- filevar = nvars++;
- s += 2;
- }
- else if (*s == '%' && s[1] == 'm') {
- *d++ = '\\'; *d++ = '('; *d++ = '.'; *d++ = '*';
- *d++ = '\\'; *d++ = ')';
- msgvar = nvars++;
- s += 2;
- }
- else if (*s == '%' && s[1] == 'l') {
- *d++ = '\\'; *d++ = '(';
- *d++ = '['; *d++ = '0'; *d++ = '-'; *d++ = '9'; *d++ = ']';
- *d++ = '*';
- *d++ = '\\'; *d++ = ')';
- s += 2;
- linevar = nvars++;
- }
- else *d++ = *s++;
- }
-
- errdfa = re_comp(errpato);
-
- while (status = runc(argv, errname)) {
- if ((srcname = merge(errname, mergename)) == NULL) {
- listerrs(errname);
- exit (status); /* couldn't merge */
- }
- edit(mergename);
- (void) unlink(errname);
-
- signal(SIGINT, SIG_IGN);
- signal(SIGTERM, SIG_IGN);
- signal(SIGHUP, SIG_IGN);
-
- unmerge(mergename, srcname);
- (void) unlink(mergename);
-
- signal(SIGINT, quit);
- signal(SIGTERM, quit);
- signal(SIGHUP, quit);
-
- if (chksum1 == chksum2) /* file unchanged ? */
- break;
-
- putchar(' ');
- for (i = 0; i < argc; i++)
- (void) printf("%s ", argv[i]);
- putchar('\n');
- }
- listerrs(errname);
- (void) unlink(errname);
- exit (status);
- }
-
- char *alloc(siz)
- {
- char *calloc();
- char *r;
- r = calloc(1, siz);
- if (!r)
- {
- fprintf(stderr, "no memory\n");
- exit(0);
- }
- return r;
- }
-